package com.socket.config;

import com.socket.config.webSocket.MyChannelInterceptor;
import com.socket.utils.LogUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
import org.springframework.web.socket.handler.WebSocketHandlerDecorator;
import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;

@Configuration
@EnableWebSocketMessageBroker//通过@EnableWebSocketMessageBroker 注解开启使用STOMP 协议来传输基于代理（message broker）的消息
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    //心跳
//    private static long HEART_BEAT = 120000;//大概8分钟断开
//    private static long HEART_BEAT = 60000;//大概2.5分钟断开
    private static long HEART_BEAT = 30000;//大概1.5~2分钟断开，测试前端断点卡1分20秒，会导致客户端未能及时发送PING导致断开

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //注册STOMP 协议的节点（endpoint），并映射的指定的URL/指定使用SockJS 协议
        System.out.println("**********************注册一个STOMP 的endpoint，并指定使用SockJS 协议********************");
        registry.addEndpoint("endpoint", "/portfolio", "/endpointWisely", "/endpointOyzc", "/endpointOueue", "endpointChat")
//                .addInterceptors(new MyHandshakeInterceptor())
                .setAllowedOrigins("*").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //配置消息代理（Message Broker）
        LogUtil.debug("**********************广播式应配置一个/topic 消息代理********************");
        LogUtil.info("**********************广播式应配置一个/topic 消息代理********************");
        LogUtil.error("**********************广播式应配置一个/topic 消息代理********************");
        LogUtil.warn("**********************广播式应配置一个/topic 消息代理********************");
        //注意：setHeartbeatValue这个不能单独设置，不然不起作用，要配合后面setTaskScheduler才可以生效
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(1);
        taskScheduler.setThreadNamePrefix("wss-heartbeat-thread-");
        taskScheduler.initialize();

        //客户端订阅消息的消息代理【SUBSCRIBE】
        //点对点应配置一个/user消息代理，广播式应配置一个/topic消息代理,群发（mass），单独聊天（alone）
        registry.enableSimpleBroker("/topic", "/user", "/queue", "/mass", "/alone")
                .setHeartbeatValue(new long[]{HEART_BEAT, HEART_BEAT}).setTaskScheduler(taskScheduler);
        ;
        //setHeartbeatValue是配置心跳，setTaskScheduler使用一个线程发送心跳

        //客户端发送消息的消息代理【SEND】
        // 全局使用的消息前缀（客户端订阅路径上会体现出来）
        //registry.setApplicationDestinationPrefixes("/app");

        //点对点使用的订阅前缀（客户端订阅路径上会体现出来），不设置的话，默认也是/user/
        registry.setUserDestinationPrefix("/user");
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        //消息拦截
        registration.interceptors(new MyChannelInterceptor());
    }

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        //"sendTimeLimit" 和"sendBufferSizeLimit",用于配置允许发送多长时间以及在向客户端发送消息时可以缓冲多少数据
        registration.setSendTimeLimit(60 * 1000);
        registration.setMessageSizeLimit(100 * 1024 * 1024);
        registration.setSendBufferSizeLimit(1024 * 1024 * 1024);

        registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
            @Override
            public WebSocketHandler decorate(WebSocketHandler handler) {
                return new WebSocketHandlerDecorator(handler) {
                    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
                        LogUtil.info("socket连接 sessionId={}, uri={}", session.getId(), session.getUri());
                        super.afterConnectionEstablished(session);
                    }

                    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
                        LogUtil.error("socket断开 sessionId={}, {}", session.getId(), closeStatus);
                    }
                };
            }
        });
    }

}
